/*
 * @(#)Request.java
 *
 *
 *
 * ver 1.0 Aug 30, 2007 ggranum
 */
package org.testfire.agent.httpserver;

import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.httpclient.HttpStatus;
import org.testfire.support.StringOutputStream;

// eof: Request.java

public class Response
{

    private int statusCode = HttpStatus.SC_OK;

    private final String CRLF = "\r\n";

    public static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat( "EEE, d MMM yyyy HH:mm:ss z" );

    private Map<String, Object> parameters = new HashMap<String, Object>();

    private Map<String, String> headers = new HashMap<String, String>();

    private StringBuilder body = new StringBuilder();

    public Response()
    {
        headers.put( "X-Powered-By", "Test Fire Agent Server 0.1" );
        headers.put( "Server", "Test Fire Agent Server 0.1" );
        headers.put( "Content-Type", "text/html;charset=UTF-8" );

    }

    public void flushToSocketWriter( PrintWriter out )
    {
        out.print( "HTTP/1.0 " + this.statusCode + " " + HttpStatus.getStatusText( this.statusCode ) + CRLF );
        out.print( "Date:" + DATE_TIME_FORMAT.format( new Date() ) + CRLF );
        out.print( mapToResponseString( headers ) );
        out.print( mapToResponseString( parameters ) );
        byte[] body = this.getBody();
        out.print( "Content-Length: " + body.length + CRLF );
        out.print( CRLF );
        out.print( body );
    }

    private String mapToResponseString( Map<String, ? extends Object> map )
    {

        try
        {
            StringBuilder b = new StringBuilder();
            for ( String key : map.keySet() )
            {
                Object o = map.get( key );
                if ( o instanceof String[] )
                {
                    String[] ary = (String[])o;
                    for ( String s : ary )
                    {
                        b.append( key ).append( ": " ).append( URLEncoder.encode( s, "UTF-8" ) ).append( CRLF );
                    }
                }
                else
                {
                    b.append( key ).append( ": " ).append( URLEncoder.encode( o.toString(), "UTF-8" ) ).append( CRLF );
                }
            }

            return b.toString();
        }
        catch ( UnsupportedEncodingException e )
        {
            throw new RuntimeException( e );
        }
    }

    public Map<String, Object> getParameterMap()
    {
        return parameters;
    }

    public void putParameter( String key, String value )
    {
        parameters.put( key, value );
    }

    public void putParameters( String key, String[] value )
    {
        parameters.put( key, value );
    }

    public String getParameter( String key )
    {
        return (String)parameters.get( key );
    }

    public String[] getParameters( String key )
    {
        return (String[])parameters.get( key );
    }

    public int getStatusCode()
    {
        return statusCode;
    }

    public void setStatusCode( int statusCode )
    {
        this.statusCode = statusCode;
    }

    public Response append( String str )
    {
        body.append( str );
        return this;
    }

    public Response deleteFromBody( int start, int end )
    {
        body.delete( start, end );
        return this;
    }

    public Response insertIntoBody( int offset, String str )
    {
        body.insert( offset, str );
        return this;
    }

    public int getBodyLength()
    {
        return body.length();
    }

    public byte[] getBody()
    {
        try
        {
            return body.toString().getBytes( "UTF-8" );
        }
        catch ( UnsupportedEncodingException e )
        {
            throw new RuntimeException( e );
        }
    }

    public void setError( Throwable error )
    {
        this.setStatusCode( HttpStatus.SC_INTERNAL_SERVER_ERROR );
        putParameter( "error_message", error.getMessage() );
        putParameter( "error_trace", StringOutputStream.printException( error ) );
    }
}